/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.common.xml;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.yzbdl.lanius.orchestrate.common.constant.Const;
import org.yzbdl.lanius.orchestrate.common.exception.runtime.XMLException;

/**
 * XML解析执行器
 *
 * @author jinchunzhao@yzbdl.ac.cn
 * @date 2022-04-26 14:21
 */
public class XMLHandler {

    public XMLHandler() {}

    /**
     * 获取xml头
     *
     * @return
     *       xml头
     */
    public static String getXMLHeader() {
        return getXMLHeader("UTF-8");
    }

    /**
     * 获取xml头
     *
     * @param encoding
     *        编码
     * @return
     *        xml头
     */
    public static String getXMLHeader(String encoding) {
        return "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>" + Const.CR;
    }

    /**
     * 获取节点集合
     *
     * @param node
     *        节点
     *
     * @param tag
     *        标记
     * @return
     *        节点集合
     */
    public static List<Node> getNodes(Node node, String tag) {
        List<Node> nodes = new ArrayList();
        if (Objects.isNull(node)) {
            return nodes;
        } else {
            NodeList children = node.getChildNodes();

            for (int i = 0; i < children.getLength(); ++i) {
                Node childnode = children.item(i);
                if (childnode.getNodeName().equalsIgnoreCase(tag)) {
                    nodes.add(childnode);
                }
            }

            return nodes;
        }
    }

    /**
     * 获取子节点
     *
     * @param node
     *        节点
     * @param tag
     *        标记
     * @return
     *        子节点
     */
    public static Node getSubNode(Node node, String tag) {
        if (Objects.isNull(node)) {
            return null;
        } else {
            NodeList children = node.getChildNodes();

            for (int i = 0; i < children.getLength(); ++i) {
                Node childnode = children.item(i);
                if (childnode.getNodeName().equalsIgnoreCase(tag)) {
                    return childnode;
                }
            }

            return null;
        }
    }

    /**
     * 获取节点值
     *
     * @param node
     *        节点
     * @return
     *        节点值
     */
    public static String getNodeValue(Node node) {
        if (Objects.isNull(node)) {
            return null;
        } else {
            NodeList children = node.getChildNodes();

            for (int i = 0; i < children.getLength(); ++i) {
                Node childnode = children.item(i);
                String retval = childnode.getNodeValue();
                if (retval != null) {
                    return retval;
                }
            }

            return null;
        }
    }

    /**
     * 加载XML
     *
     * @param content
     *        xml
     * @return
     *        Document
     * @throws Exception
     *         Exception
     */
    public static Document loadXmlString(String content) throws Exception {
        return loadXmlString(content, Boolean.FALSE, Boolean.TRUE);
    }

    /**
     * 加载XML
     *
     * @param content
     *         xml
     * @param namespaceAware
     *        是否自动创建名称空间
     * @param deferNodeExpansion
     *        true/false
     * @return Document
     * @throws XMLException
     *         XMLException
     */
    public static Document loadXmlString(String content, Boolean namespaceAware, Boolean deferNodeExpansion)
        throws XMLException {
        DocumentBuilder db = createDocumentBuilder(namespaceAware, deferNodeExpansion);
        return loadXmlString(db, content);
    }

    /**
     * 加载xml
     *
     * @param db
     *        DocumentBuilder对象
     * @param content
     *        xml内容
     * @return
     *        文档对象
     * @throws XMLException
     *         XMLException
     */
    public static Document loadXmlString(DocumentBuilder db, String content) throws XMLException {
        try {
            StringReader stringReader = new StringReader(content);
            InputSource inputSource = new InputSource(stringReader);

            Document doc;
            try {
                doc = db.parse(inputSource);
            } catch (IOException var10) {
                throw new XMLException("Error parsing XML", var10);
            } finally {
                stringReader.close();
            }

            return doc;
        } catch (Exception var12) {
            throw new XMLException("Error reading information from XML string : " + Const.CR + content, var12);
        }
    }

    /**
     * 创建DocumentBuilder对象
     *
     * @param namespaceAware
     *        是否自动创建名称空间
     * @param deferNodeExpansion
     *        true/false
     * @return Document
     * @throws XMLException
     *         XMLException
     */
    public static DocumentBuilder createDocumentBuilder(boolean namespaceAware, boolean deferNodeExpansion)
        throws XMLException {
        try {
            DocumentBuilderFactory dbf = XMLParserFactoryProducer.createSecureDocBuilderFactory();
            dbf.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", deferNodeExpansion);
            dbf.setNamespaceAware(namespaceAware);
            return dbf.newDocumentBuilder();
        } catch (ParserConfigurationException var3) {
            throw new XMLException(var3);
        }
    }

    /**
     * 获取类名称
     *
     * @return
     *        类名称
     */
    public static String getString() {
        return XMLHandler.class.getName();
    }

    /**
     * 获取子节点的名称集合
     *
     * @param node
     *        节点
     * @return
     *        子节点名称集合
     */
    public static String[] getNodeElements(Node node) {
        List<String> elements = new ArrayList();
        NodeList nodeList = node.getChildNodes();
        if (Objects.isNull(nodeList)) {
            return null;
        } else {
            for (int i = 0; i < nodeList.getLength(); ++i) {
                String nodeName = nodeList.item(i).getNodeName();
                if (!elements.contains(nodeName)) {
                    elements.add(nodeName);
                }
            }

            if (elements.isEmpty()) {
                return null;
            } else {
                return (String[])elements.toArray(new String[elements.size()]);
            }
        }
    }

}
